﻿using System;
using System.Collections.Generic;
using System.Linq;
using BuzzwordBingo.Interface;
using BuzzwordBingo.Interface.API;
using Moq;
using NUnit.Framework;

namespace BuzzwordBingo.Game.Test
{
    /// <summary>
    /// Summary description for EngineFixture
    /// </summary>
    [TestFixture]
    public class EngineFixture
    {
        private const int EVENTID = 1234;
        private const string FOOPARTICIPANT = "FooParticipant@foo.com";

        [Test]
        public void CreateNewEvent()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.CreateNewEvent();
        }

        [Test]
        public void AddParticipant()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.AddParticipant(FOOPARTICIPANT);
        }

        [Test]
        public void BuzzwordCategoryList()
        {
            var bingo = new Engine(CreateFooPersistence());
            Assert.AreEqual("FooCategory", bingo.GetBuzzwordCategoryList().First().Category);
        }

        [Test]
        public void SelectBuzzwordCategory()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.SelectBuzzwordCategory(2345);
        }

        [Test]
        public void SettleEvent()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.SettleEvent();
        }

        [Test]
        public void JoinBingoEvent()
        {
            var bingo = new Engine(CreateFooPersistence());
            BingoEventDto myEvent = bingo.JoinBingoEvent(EVENTID);
            Assert.IsInstanceOf(typeof(BingoEventDto), myEvent);
        }

        [Test]
        public void PlayAs()
        {
            var bingo = new Engine(CreateFooPersistence());
            // must join the bingo event first
            bingo.JoinBingoEvent(EVENTID);
            ParticipantDto myParticipant = bingo.PlayAs(EVENTID, FOOPARTICIPANT);
            Assert.IsInstanceOf(typeof(ParticipantDto), myParticipant);
            Assert.AreEqual(FOOPARTICIPANT, myParticipant.Email);
        }

        [Test]
        public void MarkBuzzword()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.JoinBingoEvent(EVENTID);
            ParticipantDto myParticipant = bingo.PlayAs(EVENTID, FOOPARTICIPANT);
            // get the buzzwords for display
            // moq does not support a multi indexing property such as BuzzWords[j,k]
            // bingo.MarkBuzzWord(EVENTID, myParticipant.Email, 0);
        }

        [Test]
        public void GetWinner()
        {
            var bingo = new Engine(CreateFooPersistence());
            bingo.JoinBingoEvent(EVENTID);
            ParticipantDto myWinner = bingo.GetWinner(EVENTID);
            Assert.IsInstanceOf(typeof(ParticipantDto), myWinner);
            Assert.AreEqual(FOOPARTICIPANT, myWinner.Email);
        }

        #region factory methods

        public IParticipant CreateFooParticipant()
        {
            var fooParticipant = new Mock<IParticipant>(MockBehavior.Loose);
            fooParticipant.ExpectGet<string>(p => p.Email).Returns(FOOPARTICIPANT);
            return fooParticipant.Object;
        }

        public IBingoEvent CreateFooBingoEvent()
        {
            var fooBingo = new Mock<IBingoEvent>(MockBehavior.Loose);
            var fooList = new List<IParticipant>();
            fooList.Add(CreateFooParticipant());
            fooBingo.Expect(b => b.ParticipantList).Returns(fooList);
            fooBingo.Expect(b => b.GetWinner()).Returns(CreateFooParticipant());
            fooBingo.ExpectGet<DateTime>(b => b.StartDate).Returns(DateTime.Now.Subtract(TimeSpan.Parse("00:05:00")));
            fooBingo.ExpectGet<DateTime>(b => b.EndDate).Returns(DateTime.Now.AddMinutes(5));
            fooBingo.ExpectGet<int>(b => b.GetId).Returns(EVENTID);
            fooBingo.Expect(b => b.Category).Returns(CreateFooBuzzwordCategory());
            return fooBingo.Object;
        }

        public IBuzzwordCategory CreateFooBuzzwordCategory()
        {
            var fooCategory = new Mock<IBuzzwordCategory>(MockBehavior.Loose);
            fooCategory.ExpectGet<string>(c => c.Category).Returns("FooCategory");
            var wordList = new List<IBuzzWord>();
            for (int i = 0; i < 35; i++)
            {
                var word = new Mock<IBuzzWord>(MockBehavior.Loose);
                word.Expect(w => w.FuzzyWord).Returns(i.ToString());
                wordList.Add(word.Object);
            }
            fooCategory.Expect(c => c.BuzzWordList).Returns(wordList);
            return fooCategory.Object;
        }

        public IPersistenceService CreateFooPersistence()
        {
            var fooPersistence = new Mock<IPersistenceService>(MockBehavior.Loose);
            fooPersistence.Expect(p => p.LoadEvent(It.IsAny<int>())).Returns(CreateFooBingoEvent());
            var fooList = new List<IBuzzwordCategory>();
            fooList.Add(CreateFooBuzzwordCategory());
            fooPersistence.Expect(p => p.LoadBuzzwordCategoryList()).Returns(fooList);
            fooPersistence.Expect(p => p.LoadBuzzwordCategory(It.IsAny<int>())).Returns(CreateFooBuzzwordCategory());
            return fooPersistence.Object;
        }

        #endregion
    }
}
